package com.tianyu.inspection.controller;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.tianyu.inspection.common.Constants;
import com.tianyu.inspection.common.enums.FileTypeEnum;
import com.tianyu.inspection.common.enums.RoState;
import com.tianyu.inspection.common.annotation.Permission;
import com.tianyu.inspection.common.component.AppConstants;
import com.tianyu.inspection.common.component.Validate;
import com.tianyu.inspection.entity.UploadFile;
import com.tianyu.inspection.entity.model.QueryMo;
import com.tianyu.inspection.entity.vo.Ro;
import com.tianyu.inspection.entity.vo.ServiceRo;
import com.tianyu.inspection.service.api.IUploadFileService;
import io.ocs.model.OcsObject;
import io.ocs.model.OcsSimpleModel;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

import static com.tianyu.inspection.common.enums.FileTypeEnum.FILE_TWO_DIMENSIONAL_MODEL;

/**********************************
 * @Author YSW
 * @Description 文件管理接口
 * @Date 2021/1/20 - 15:51
 **********************************/

@RestController
@RequestMapping("/api/2.0/file")
public class UploadFileController {

    @Resource
    private IUploadFileService uploadFileService;

    @Resource
    private Validate validateModel;

    @Resource
    private AppConstants appConstants;

    @Resource
    private OcsSimpleModel ocsSimpleModel;

    @Resource
    private ValueOperations<String, Object> valueOperations;

    @GetMapping(value = "/admin/analysis")
    @Permission(value = 1, tags = Constants.API_SUPER)
    public Ro<Object> fileStatisticalAnalysis() {
        Ro<Object> ro = new Ro<>(RoState.SUCCESS);
        Object obj = valueOperations.get(appConstants.redisFileAnalyse);
        if (Objects.nonNull(obj)) {
            ro.setContent(obj);
        } else {
            ModelMap map = uploadFileService.fileStatisticalAnalysis();
            valueOperations.set(appConstants.redisFileAnalyse, map, 7, TimeUnit.DAYS);
            ro.setContent(map);
        }
        return ro;
    }

    @DeleteMapping(value = "/admin/clean")
    @Permission(value = 1, tags = Constants.API_SUPER)
    public Ro<ModelMap> ossCleanUselessly() {
        Ro<ModelMap> ro = new Ro<>(RoState.SUCCESS);
        ModelMap map = uploadFileService.ossCleanUselessly();
        return ro.setResultEnum(RoState.SUCCESS).setContent(map);
    }

    @PostMapping(value = "/upload")
    @Permission(value = 4, tags = Constants.API_PATROL)
    public Ro<String> ossUpload(@RequestParam("file") MultipartFile multipartFile,
                                @RequestParam("category") Integer category,
                                @RequestHeader("u-projectId") Integer projectId, @RequestHeader("u-uid") Integer userId) {
        Ro<String> ro = new Ro<>(RoState.SUCCESS);
        if (multipartFile.getSize() == 0) {
            return ro.setResultEnum(RoState.FAIL).setMessage("参数错误[file]");
        }
        if (projectId == 1) {
            return ro.setResultEnum(RoState.FAIL).setMessage("超级管理员用户请使用接口[/api/2.0/file/admin/upload]");
        }
        ServiceRo serviceRo = uploadFileService.ossUpload(multipartFile, category, projectId, userId);
        if (!serviceRo.getResult()) {
            ro.setResultEnum(RoState.FAIL);
        }
        ro.setContent(serviceRo.getMessage());
        return ro;
    }

    @PostMapping(value = "/admin/upload")
    @Permission(value = 1, tags = Constants.API_SUPER)
    public Ro<String> ossAdminUpload(@RequestParam("file") MultipartFile multipartFile,
                                     @RequestParam("category") Integer category,
                                     @RequestParam("projectId") Integer projectId,
                                     @RequestHeader("u-uid") Integer userId) {
        Ro<String> ro = new Ro<>(RoState.SUCCESS);
        //文件校验
        if (Objects.isNull(multipartFile) || multipartFile.getSize() == 0) {
            return ro.setResultEnum(RoState.FAIL).setMessage("参数错误[file]");
        }
        //文件类型校验 1 2 5-15
        if (Objects.isNull(category) || category < 1 || category >= FileTypeEnum.UNKNOWN.getValue() || category == 3 || category == 4) {
            return ro.setResultEnum(RoState.FAIL).setMessage("参数错误[category]");
        }
        //项目ID校验
        if (Objects.nonNull(projectId)) {
            if (validateModel.projectIdValidate(projectId)) {
                return ro.setResultEnum(RoState.FAIL).setMessage("参数错误[projectId],值不存在");
            }
        }
        String filename = multipartFile.getOriginalFilename();
        if (Objects.nonNull(filename)) {
            //客户端文件类型
            if (category == FileTypeEnum.FILE_WIN_PROD_EXE.getValue() ||
                    category == FileTypeEnum.FILE_WIN_TEST_EXE.getValue() ||
                    category == FileTypeEnum.FILE_ANDROID_PROD_APP.getValue() ||
                    category == FileTypeEnum.FILE_ANDROID_TEST_APP.getValue()) {
                if (projectId != 1) {
                    return ro.setResultEnum(RoState.FAIL).setMessage("参数错误[projectId],值应为1");
                }
                if (category == FileTypeEnum.FILE_WIN_PROD_EXE.getValue() || category == FileTypeEnum.FILE_WIN_TEST_EXE.getValue()) {
                    if (!filename.endsWith(".exe")) {
                        return ro.setResultEnum(RoState.FAIL).setMessage("参数错误[file],非exe文件");
                    }
                }
                //图片类型限制文件后缀名
            } else if (category != 1) {
                if (!(filename.endsWith(".png") || filename.endsWith(".jpg") || filename.endsWith(".jpeg") || filename.endsWith(".ico") || filename.endsWith(".icon"))) {
                    return ro.setResultEnum(RoState.FAIL).setMessage("参数错误[file],图片文件需以[.png | .jpg | .jpeg | .ico | .icon]结尾");
                }
            }
        }
        ServiceRo serviceRo = uploadFileService.ossUpload(multipartFile, category, projectId, userId);
        if (!serviceRo.getResult()) {
            ro.setResultEnum(RoState.FAIL);
        }
        ro.setContent(serviceRo.getMessage());
        return ro;
    }

    @PostMapping(value = "/admin/uploads")
    @Permission(value = 1, tags = Constants.API_SUPER)
    public Ro<List<String>> ossUploads(@RequestParam("files") MultipartFile[] files,
                                       @RequestParam("category") Integer category,
                                       @RequestParam("projectId") Integer projectId,
                                       @RequestHeader("u-uid") Integer userId) {
        Ro<List<String>> ro = new Ro<>(RoState.SUCCESS);
        if (Objects.nonNull(projectId)) {
            if (validateModel.projectIdValidate(projectId)) {
                return ro.setResultEnum(RoState.FAIL).setMessage("参数错误[projectId],值不存在");
            }
        }
        if (Objects.isNull(category) || category < 1 || category >= FileTypeEnum.UNKNOWN.getValue() || category == 2 || category == 3 || category == 4) {
            return ro.setResultEnum(RoState.FAIL).setMessage("参数错误[category]");
        }
        if (files.length == 0) {
            return ro.setResultEnum(RoState.FAIL).setMessage("参数错误[files],请重新选择文件");
        }
        String originalFilename = files[0].getOriginalFilename();
        if (Objects.nonNull(originalFilename)) {
            for (MultipartFile multipartFile : files) {
                if (multipartFile.getSize() == 0) {
                    return ro.setResultEnum(RoState.FAIL).setMessage("参数错误[files],请重新选择文件");
                }
                String filename = multipartFile.getOriginalFilename();
                if (Objects.nonNull(filename)) {
                    if (category != 1) {
                        if (!(filename.endsWith(".png") || filename.endsWith(".jpg") || filename.endsWith(".jpeg"))) {
                            return ro.setResultEnum(RoState.FAIL).setMessage("参数错误[file],图片文件需以[.png | .jpg | .jpeg]结尾");
                        }
                    }
                }
            }
        } else {
            return ro.setResultEnum(RoState.FAIL).setMessage("参数错误[files],请重新选择文件");
        }

        if (Objects.nonNull(projectId)) {
            if (validateModel.projectIdValidate(projectId)) {
                return ro.setResultEnum(RoState.FAIL).setMessage("参数错误[projectId],值不存在");
            }
        }
        List<String> list = uploadFileService.ossUploads(files, category, projectId, userId);
        if (null == list || list.size() == 0) {
            ro.setResultEnum(RoState.FAIL);
        }
        ro.setContent(list);
        return ro;
    }

    @PostMapping(value = "/admin/download")
    @Permission(value = 1, tags = Constants.API_COMPANY)
    public HttpServletResponse download(@RequestBody QueryMo queryMo, HttpServletResponse response, @RequestHeader("u-projectId") Integer projectId) {
        queryMo.build(UploadFile.class, null);
        String url = (String) queryMo.getEqMap().get("url");
        try {
            if (Objects.isNull(url)) {
                response.reset();
                response.setContentType("application/json;charset=UTF-8");
                Ro<Void> ro = new Ro<Void>(RoState.FAIL).setMessage("缺少参数[url]");
                byte[] responseBytes = JSON.toJSONString(ro).getBytes();
                OutputStream outputStream = new BufferedOutputStream(response.getOutputStream(), responseBytes.length);
                outputStream.write(responseBytes);
                outputStream.flush();
                outputStream.close();
                return response;
            }
            OcsObject cosObject = ocsSimpleModel.getObject(url);
            if (Objects.isNull(cosObject)) {
                response.reset();
                response.setContentType("application/json;charset=UTF-8");
                Ro<Void> ro = new Ro<Void>(RoState.FAIL).setMessage("文件不存在");
                byte[] responseBytes = JSON.toJSONString(ro).getBytes();
                OutputStream outputStream = new BufferedOutputStream(response.getOutputStream(), responseBytes.length);
                outputStream.write(responseBytes);
                outputStream.flush();
                outputStream.close();
                return response;
            }
            try {
                response.reset();
                response.addHeader("Content-Length", "" + cosObject.getContentLength());
                response.setStatus(200);
                final InputStream inputStream = cosObject.getInputStream();
                OutputStream outputStream = new BufferedOutputStream(response.getOutputStream(), Math.toIntExact(cosObject.getContentLength()));
                outputStream.write(Math.toIntExact(cosObject.getContentLength()));
                byte[] buffer = new byte[1024];
                int len;
                while ((len = inputStream.read(buffer)) != -1) {
                    outputStream.write(buffer, 0, len);
                }
                outputStream.flush();
                outputStream.close();
                inputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        } catch (Exception exception) {
            return response;
        }
        return response;
    }

    @GetMapping(value = "/admin/list")
    @Permission(value = 1, tags = Constants.API_SUPER)
    public Ro<IPage<UploadFile>> getPageList(HttpServletRequest request, @RequestHeader("u-projectId") Integer projectId) {
        QueryMo queryMo = QueryMo.getQueryMo(request);
        Ro<IPage<UploadFile>> ro = new Ro<>();
        queryMo.build(UploadFile.class, projectId);
        return ro.setContent(uploadFileService.searchListPage(queryMo));
    }

    @GetMapping(value = "/admin/{id}")
    @Permission(value = 1, tags = Constants.API_SUPER)
    public Ro<UploadFile> getOne(@PathVariable Integer id, @RequestHeader("u-projectId") Integer projectId) {
        Ro<UploadFile> ro = new Ro<>();
        if (Objects.isNull(id)) {
            return ro.setResultEnum(RoState.PARAMS_MISS_ERROR);
        }
        QueryMo queryMo = new QueryMo();
        queryMo.put("id", id);
        queryMo.build(UploadFile.class, projectId);
        UploadFile uploadFile = uploadFileService.selectOne(queryMo);
        if (Objects.isNull(uploadFile)) {
            ro.setMessage("未查询到数据");
        } else {
            ro.setContent(uploadFile);
        }
        return ro;
    }

    @DeleteMapping(value = "/admin/delete/{id}")
    @Permission(value = 1, tags = Constants.API_SUPER)
    public Ro<UploadFile> delete(@PathVariable Integer id, @RequestHeader("u-projectId") Integer projectId) {
        Ro<UploadFile> ro = new Ro<>();
        QueryMo queryMo = new QueryMo();
        queryMo.put("id", id);
        queryMo.build(UploadFile.class, projectId);
        if (!uploadFileService.delete(queryMo)) {
            ro.setResultEnum(RoState.FAIL).setMessage("无匹配ID,删除失败");
        }
        return ro;
    }

    @DeleteMapping(value = "/admin/delete/logical/{id}")
    @Permission(value = 1, tags = Constants.API_SUPER)
    public Ro<UploadFile> logicallyDelete(@PathVariable Integer id, @RequestHeader("u-projectId") Integer projectId) {
        Ro<UploadFile> ro = new Ro<>();
        QueryMo queryMo = new QueryMo();
        queryMo.put("id", id);
        queryMo.build(UploadFile.class, projectId);
        if (!uploadFileService.logicallyDelete(queryMo)) {
            ro.setResultEnum(RoState.FAIL).setMessage("无匹配ID,删除失败");
        }
        return ro;
    }
}
